#include "umSource.h"
#include "umSink.h"
#include "umlog.h"
#include "umapi_socket.h"
#include "umSink.h"
#include "umlog.h"

#define TARGET "PKSOUTCE"

typedef struct
{
	S_SOURCE *source;
	UM_CHAR outFmt[10];
	UM_S32 vId,vF, vW,vH, aId,aF,aR,aC,aS;
	UM_S32 vCodeId,aCodeId;
	UM_S32 vbits,abits;
	AVFormatContext *pav;
	UM_U8 *otsbuf;
	UM_HANDLE mutexHandle;
	struct umapi_list_head sinks;
}S_PKCONTEXT;

#define CREATEAV(dst, ww, hh, vcid, vf, vbits, auid, ar, ac, abits) do{ \
		AVStream * avStream = avformat_new_stream(dst, NULL); \
		avStream->id = 0; \
		avStream->codecpar->width  = ww; \
		avStream->codecpar->height = hh; \
	    avStream->codecpar->codec_type =  AVMEDIA_TYPE_VIDEO; \
	    avStream->codecpar->codec_id   = vcid; \
		avStream->codecpar->format 	   = AV_PIX_FMT_YUVJ420P; \
	    avStream->codecpar->bit_rate   = vbits; \
	    avStream->time_base = (AVRational){ 1, 90000 }; \
	    avStream->r_frame_rate = (AVRational){ vf, 1 }; \
	    avStream->avg_frame_rate = (AVRational){ vf, 1 }; \
		AVStream * avStream1 = avformat_new_stream(dst, NULL); \
		avStream1->id = 1; \
		avStream1->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; \
		avStream1->codecpar->codec_id = auid; \
		avStream1->codecpar->format = AV_SAMPLE_FMT_FLTP; \
		avStream1->codecpar->sample_rate = ar; \
		avStream1->codecpar->bit_rate	= abits;  \
		avStream1->nb_frames = 1; \
		avStream1->codecpar->channels = ac; \
		avStream1->time_base = (AVRational){ 1, 90000 }; \
	}while(0)
	
static int write_tspacket(UM_VOID *opaque, UM_U8 *buf, UM_S32 buf_size)
{    
	AVPacket pkt;
	pkt.data = buf;
	pkt.size = buf_size;
	struct umapi_list_head *pos, *n;
	S_PKCONTEXT * pPk = (S_PKCONTEXT*)opaque;
	umapi_list_for_each_safe(pos, n, &pPk->sinks)
	{
		S_SINK *sink = umapi_list_entry(pos,S_SINK, head);
		if(sink->writePacket)
		{
			sink->writePacket(sink, &pkt);
		}
	}
    return buf_size;
}

static int64_t seek_tspacket(UM_VOID *opaque, int64_t offset, UM_S32 whence)
{
    return offset;
}

static UM_S32 decParams(S_PKCONTEXT *pPk)
{
	UM_CHAR * urlParam = umapi_strstr(pPk->source->sourceUrl, "?");
	if(!urlParam || !urlParam++)
		return UM_FAILURE;
	readStringByUrl(urlParam, "out", pPk->outFmt);
	UM_CHAR value[255];
	UM_CHAR codeId[20];
	value[0] = '\0';
	readStringByUrl(urlParam, "v", value);
	if(umapi_strlen(value) >0)
	{
		umapi_sscanf(value, "%d,%d,%d,%d,%d,%s", &pPk->vId, &pPk->vF, &pPk->vW,&pPk->vH, &pPk->vbits, codeId);
		AVCodec * ac = avcodec_find_encoder_by_name(codeId);
		if(!ac)
			return UM_FAILURE;
		pPk->vCodeId = ac->id;
	}
	value[0] = '\0';
	readStringByUrl(urlParam, "a", value);
	if(umapi_strlen(value) >0)
	{
		umapi_sscanf(value, "%d,%d,%d,%d,%s",&pPk->aId, &pPk->aR, &pPk->aC, &pPk->abits, codeId);
		AVCodec * ac = avcodec_find_encoder_by_name(codeId);
		if(!ac)
			return UM_FAILURE;
		pPk->aCodeId = ac->id;
	}
	LOGI("surl:%s, vParam:{id:%d,f:%d,w:%d,h:%d,bits:%d,codecId:%d},"
		"aParam:{id:%d,sample_rate:%d,channels:%d,abits:%d,codecId:%d}", 
		pPk->source->sourceUrl, 
		pPk->vId, pPk->vF, pPk->vW, pPk->vH, pPk->vbits, pPk->vCodeId,
		pPk->aId, pPk->aR, pPk->aC, pPk->abits, pPk->aCodeId);
	return UM_SUCCESS;
}
static UM_S32 sendDataToSinks(UM_VOID *pSource, AVPacket *pkt)
{
	
}
AVFormatContext* getAvIn(UM_VOID *pSource)
{
	S_PKCONTEXT *p = GETCONTEXT(S_PKCONTEXT *, pSource); 
	return p->pav;
}

static UM_S32 init(S_PKCONTEXT *pPk, S_SOURCE *pSource)
{
	pPk->source = pSource;
	umapi_sprintf(pPk->outFmt,"%s","ts");
	pPk->vId = pPk->aId = -1;
	decParams(pPk);
	LOGI("pack format:%s, vId,vF, vW,vH, aId,aF,aR,aC,aS ", pPk->outFmt,
		pPk->vId,pPk->vF, pPk->vW,pPk->vH, pPk->aId,pPk->aF,pPk->aR,pPk->aC,pPk->aS);
	avformat_alloc_output_context2(&pPk->pav, NULL, pPk->outFmt, NULL); 
	CREATEAV(pPk->pav, pPk->vW, pPk->vH, pPk->vCodeId, pPk->vF, pPk->vbits,pPk->aCodeId,pPk->aR, pPk->aC, pPk->aS);	
	#define CACHEBUFFSIZE (4*1024*1024)
	pPk->otsbuf = (UM_U8 *)umapi_malloc(CACHEBUFFSIZE);
	((AVFormatContext *)(pPk->pav))->pb = avio_alloc_context(pPk->otsbuf, CACHEBUFFSIZE, 1, pPk, NULL, 
        write_tspacket, seek_tspacket);
	umapi_list_create(&pPk->sinks);
    av_dump_format(pPk->pav, 0, pPk->source->sourceUrl, 1);
	UM_S32 s32ret = avformat_write_header(pPk->pav, NULL);
	return UM_SUCCESS;
}
static UM_VOID deinit(S_PKCONTEXT *pPk)
{
	avio_context_free(&pPk->pav->pb);
	avformat_free_context(pPk->pav);
	umapi_free(pPk->otsbuf);
	return ;
}

BASICSOURCEFUN(S_PKCONTEXT, init, deinit);


S_SOURCE pkSource = 
{
    .protocol = "pk",
	.describe = "avPacket==>avStream",
    .open = open,
    .open2 = open2,
    .addSink = addSink,
    .delSink = delSink,
    .start =  start,
    .stop = stop,
    .destroy = destroy,
    .getAvIn = getAvIn,
    .priSize = sizeof(S_PKCONTEXT),
};
    
